package cn.maihe.elg.operation.supports.sms;

import cn.maihe.elg.operation.common.Constants;
import cn.maihe.elg.operation.config.HuaWeiSmsConfig;
import com.cloud.apigateway.sdk.utils.Client;
import com.cloud.apigateway.sdk.utils.Request;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;

@Service
@Slf4j
public class HuaWeiCloudSmsService {
    public static final String UTF_8 = "UTF-8";
    private static CloseableHttpClient client = null;
    private HuaWeiSmsConfig huaWeiSmsConfig;

    public static void main(String[] args) throws Exception {
        // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
        client = createIgnoreSSLHttpClient();
        sendSms();
//        String[] param={"12312","234324"};
//        System.out.println(JSON.toJSONString(param));
//        System.out.println(Arrays.toString(param));
    }

    public HuaWeiCloudSmsService(HuaWeiSmsConfig huaWeiSmsConfig) throws Exception {
        Assert.hasText(huaWeiSmsConfig.getUrl(), "huawei.sms.url未配置");
        Assert.hasText(huaWeiSmsConfig.getAppKey(), "huawei.sms.appKey未配置");
        Assert.hasText(huaWeiSmsConfig.getAppSecret(), "huawei.sms.appSecret未配置");
        Assert.hasText(huaWeiSmsConfig.getSender(), "huawei.sms.sender未配置");
        Assert.hasText(huaWeiSmsConfig.getTemplateId(), "huawei.sms.templateId未配置");
        Assert.hasText(huaWeiSmsConfig.getSignature(), "huawei.sms.signature未配置");
        this.huaWeiSmsConfig = huaWeiSmsConfig;

        //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
        client = createIgnoreSSLHttpClient();
//        // 创建一个连接池 httpclient, 并设置最大连接量为10
//        PoolingHTTPClient httpclient = new PoolingHTTPClient(10);
//        this.ssender = new SmsSingleSender(tencentSmsConfig.getAppid(), tencentSmsConfig.getAppkey(),httpclient);

    }

    /**
     * 若异常则 保存发送内容，间隔多久重新发送，重试几次均失败则丢弃，其他则标识发送成功
     *
     * @param receiver      必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
     * @param templateId    选填 模板ID 传入空值自动使用默认的模板ID
     * @param templateParas * 选填,使用无变量模板时请赋空值 String templateParas = "";
     *                      * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]",杜绝首位0丢失的问题（例如：002569变成了2569）
     *                      * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
     */
    public void sendSms(String receiver, String templateId, String templateParas) {
        try {
            //请求Body,不携带签名名称时,signature请填null
            if (StringUtils.isBlank(templateId)) {
                templateId = huaWeiSmsConfig.getTemplateId();
            }
            String body = buildRequestBody(huaWeiSmsConfig.getSender(), receiver, templateId, templateParas, huaWeiSmsConfig.getStatusCallBack(), huaWeiSmsConfig.getSignature());
            if (null == body || body.isEmpty()) {
                log.warn("body is null.");
                return;
            }

            Request request = new Request();
            request.setKey(huaWeiSmsConfig.getAppKey());
            request.setSecret(huaWeiSmsConfig.getAppSecret());
            request.setMethod("POST");
            request.setUrl(huaWeiSmsConfig.getUrl());
            request.addHeader("Content-Type", "application/x-www-form-urlencoded");
            request.setBody(body);
            log.info("Print the body: {}", body);


            HttpRequestBase signedRequest = Client.sign(request, Constants.SIGNATURE_ALGORITHM_SDK_HMAC_SHA256);
            log.info("Print the authorization: {}", Arrays.toString(signedRequest.getHeaders("Authorization")));
            Header[] requestAllHeaders = signedRequest.getAllHeaders();
            for (Header h : requestAllHeaders) {
                log.info("req Header with name: {} and value: {}", h.getName(), h.getValue());
            }

            HttpResponse response = client.execute(signedRequest);

            log.info("Print the status line of the response: {}", response.getStatusLine().toString());
            Header[] resHeaders = response.getAllHeaders();
            for (Header h : resHeaders) {
                log.info("Processing Header with name: {} and value: {}", h.getName(), h.getValue());
            }
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                log.info("Processing Body with name: {} and value: {}", System.getProperty("line.separator"),
                        EntityUtils.toString(resEntity, "UTF-8"));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private static void sendSms() throws IOException {
        //必填,请参考"开发准备"获取如下数据,替换为实际值
        String url = "https://smsapi.cn-south-1.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址+接口访问URI
        // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全；
        String appKey = "x9N52rW5kY0l3yL8816dVXv3Zq41"; //Application Key
        String appSecret = "Zl3NvgKlHZ7bK0D4TXcDWPwLXt55"; //Application Secret
        String sender = "cs106900001938"; //中国大陆短信签名通道号或全球短信通道号
        String templateId = "7d12a2902a934b8096114472e9d18a7b"; //模板ID

        //条件必填,中国大陆短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
        //全球短信不用关注该参数
        String signature = "华为云测试签名"; //签名名称

        //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
        String receiver = "+8618350160612"; //短信接收人号码

        //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
        String statusCallBack = "";

        /**
         * 选填,使用无变量模板时请赋空值 String templateParas = "";
         * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]"
         * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
         * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
         */
        String templateParas = "[\"111111\"]"; //模板变量，此处以单变量验证码短信为例，请客户自行生成6位验证码，并定义为字符串类型，以杜绝首位0丢失的问题（例如：002569变成了2569）。

        //请求Body,不携带签名名称时,signature请填null
        String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature);
        if (null == body || body.isEmpty()) {
            log.warn("body is null.");
            return;
        }

        Request request = new Request();
        request.setKey(appKey);
        request.setSecret(appSecret);
        request.setMethod("POST");
        request.setUrl(url);
        request.addHeader("Content-Type", "application/x-www-form-urlencoded");
        request.setBody(body);
        log.info("Print the body: {}", body);

        try {
            HttpRequestBase signedRequest = Client.sign(request, Constants.SIGNATURE_ALGORITHM_SDK_HMAC_SHA256);
            log.info("Print the authorization: {}", Arrays.toString(signedRequest.getHeaders("Authorization")));
            Header[] requestAllHeaders = signedRequest.getAllHeaders();
            for (Header h : requestAllHeaders) {
                log.info("req Header with name: {} and value: {}", h.getName(), h.getValue());
            }

            HttpResponse response = client.execute(signedRequest);

            log.info("Print the status line of the response: {}", response.getStatusLine().toString());
            Header[] resHeaders = response.getAllHeaders();
            for (Header h : resHeaders) {
                log.info("Processing Header with name: {} and value: {}", h.getName(), h.getValue());
            }
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                log.info("Processing Body with name: {} and value: {}", System.getProperty("line.separator"),
                        EntityUtils.toString(resEntity, "UTF-8"));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public static CloseableHttpClient createIgnoreSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (x509CertChain, authType) -> true).build();
        return HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    }

    static String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
                                   String statusCallBack, String signature) throws UnsupportedEncodingException {
        if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty()
                || templateId.isEmpty()) {
            System.out.println("buildRequestBody(): sender, receiver or templateId is null.");
            return null;
        }

        StringBuilder body = new StringBuilder();
        appendToBody(body, "from=", sender);
        appendToBody(body, "&to=", receiver);
        appendToBody(body, "&templateId=", templateId);
        appendToBody(body, "&templateParas=", templateParas);
        appendToBody(body, "&statusCallback=", statusCallBack);
        appendToBody(body, "&signature=", signature);
        return body.toString();
    }

    private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException {
        if (null != val && !val.isEmpty()) {
            log.info("Print appendToBody: {}:{}", key, val);
            body.append(key).append(URLEncoder.encode(val, UTF_8));
        }
    }
}


